package com.dieusoft.box.bill.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dieusoft.box.bill.entity.InvoiceInfo;
import com.dieusoft.box.bill.service.IInvoiceService;
import com.dieusoft.box.bill.vo.InvoiceInfoVO;
import com.dieusoft.box.bill.vo.InvoiceQueryVO;
import com.dieusoft.box.ship.entity.ShipExport;
import com.dieusoft.box.ship.service.ShipExportService;
import com.dieusoft.box.trade.entity.CostInfo;
import com.dieusoft.box.trade.entity.JzxTrade;
import com.dieusoft.box.trade.service.ICostInfoService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 发票管理
 * @Author: dongw
 * @Date: 2021-03-22
 * @Version: V1.0
 */
@Api(tags = "发票管理")
@RestController
@RequestMapping("/invoice")
@Slf4j
public class InvoiceController {

    @Autowired
    private ShipExportService shipExportService;

    @Autowired
    private ICostInfoService costInfoService;

    @Autowired
    private IInvoiceService invoiceService;


    @GetMapping(value = "/query/list")
    public Result<?> queryPageList(InvoiceQueryVO invoiceQueryVo) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        QueryWrapper<ShipExport> shipExportQueryWrapper = new QueryWrapper<>();
        shipExportQueryWrapper.eq("sys_org_code", sysUser.getOrgCode());
        if (StringUtils.isNotBlank(invoiceQueryVo.getMainOffNumber())) {
            shipExportQueryWrapper.like("main_off_number", invoiceQueryVo.getMainOffNumber());
        } else if (StringUtils.isNotBlank(invoiceQueryVo.getOtherOffNumber())) {
            shipExportQueryWrapper.like("other_off_number", invoiceQueryVo.getOtherOffNumber());
        } else if (StringUtils.isNotBlank(invoiceQueryVo.getCustomerNumber())) {
            shipExportQueryWrapper.like("customer_number", invoiceQueryVo.getCustomerNumber());
        } else if (StringUtils.isNotBlank(invoiceQueryVo.getEtdEnd()) && StringUtils.isNotBlank(invoiceQueryVo.getEtdStart())) {
            shipExportQueryWrapper.between("etd", invoiceQueryVo.getEtdStart(), invoiceQueryVo.getEtdEnd());
        }

        List<ShipExport> shipExportList = shipExportService.list(shipExportQueryWrapper);

        List<String> ids = shipExportList.stream().map(ShipExport::getId).collect(Collectors.toList());

        if (ids.size() == 0) {
            return Result.OK(Collections.EMPTY_LIST);
        } else {
            QueryWrapper<CostInfo> costInfoQueryWrapper = new QueryWrapper<>();
//            costInfoQueryWrapper.eq("create_by", sysUser.getUsername());
            costInfoQueryWrapper.like("s_code", 3);
            costInfoQueryWrapper.like("type", "ys");

            costInfoQueryWrapper.in("buis_id", ids);
            if (StringUtils.isNotBlank(invoiceQueryVo.getSettlementCompany())) {
                costInfoQueryWrapper.like("settlement_company", invoiceQueryVo.getSettlementCompany());
            }
            if (StringUtils.isNotBlank(invoiceQueryVo.getCostName())) {
                costInfoQueryWrapper.like("cost_name", invoiceQueryVo.getCostName());
            }
            if (StringUtils.isNotBlank(invoiceQueryVo.getCurrency())) {
                costInfoQueryWrapper.like("currency", invoiceQueryVo.getCurrency());
            }
            List<CostInfo> costInfoList = costInfoService.list(costInfoQueryWrapper);
            return Result.OK(costInfoList);
        }

    }

    @GetMapping(value = "/list")
    public Result list(InvoiceQueryVO invoiceQueryVo,
                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        QueryWrapper<InvoiceInfo> queryWrapper = new QueryWrapper();
        if (StringUtils.isNotBlank(invoiceQueryVo.getSettlementCompany())) {
            queryWrapper.like("settlement_company", invoiceQueryVo.getSettlementCompany());
        }
        if (StringUtils.isNotBlank(invoiceQueryVo.getInvoiceNumber())) {
            queryWrapper.like("invoice_number", invoiceQueryVo.getInvoiceNumber());
        }
        if (StringUtils.isNotBlank(invoiceQueryVo.getInvoiceSerial())) {
            queryWrapper.like("invoice_serial", invoiceQueryVo.getInvoiceSerial());
        }
        if (null != invoiceQueryVo.getFeeStatus()) {
            queryWrapper.eq("fee_status", invoiceQueryVo.getFeeStatus());
        }
        if (null != invoiceQueryVo.getStatus()) {
            queryWrapper.eq("status", invoiceQueryVo.getStatus());
        }
        if (!StringUtils.isAnyBlank(invoiceQueryVo.getBillDateStart(), invoiceQueryVo.getBillDateEnd())) {
            queryWrapper.between("bill_date", invoiceQueryVo.getBillDateStart(), invoiceQueryVo.getBillDateEnd());
        }
        if (!StringUtils.isAnyBlank(invoiceQueryVo.getCreateDateStart(), invoiceQueryVo.getCreateDateEnd())) {
            queryWrapper.between("create_time", invoiceQueryVo.getCreateDateStart(), invoiceQueryVo.getCreateDateEnd());
        }
        Page<InvoiceInfo> page = new Page<InvoiceInfo>(pageNo, pageSize);
        IPage<InvoiceInfo> pageList = invoiceService.page(page);
        return Result.OK(pageList);
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @DeleteMapping(value = "/delete")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        InvoiceInfo invoiceInfo = invoiceService.getById(id);
        if (null == invoiceInfo) {
            return Result.error("单据不存在");
        }
        String[] invoiceSerialSplit = invoiceInfo.getInvoiceSerial().split("-");
        //如果删除的不是继续开票的申请单需要对里面的费用状态进行回滚
        if (invoiceSerialSplit.length == 1) {
            String costIds = invoiceInfo.getCostIds();
            UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
            costInfoUpdateWrapper.set("s_code", 3);
            costInfoUpdateWrapper.set("status", "审核通过");
            costInfoUpdateWrapper.eq("type", "ys");
            costInfoUpdateWrapper.in("id", Arrays.asList(costIds.split(",")));
            costInfoService.update(costInfoUpdateWrapper);
        } else {
            String mainId = invoiceSerialSplit[0];
            String serial = invoiceSerialSplit[1];
            if (Integer.parseInt(serial) == 1) {
                invoiceService.update(new UpdateWrapper<InvoiceInfo>().set("is_surplus", 1).eq("invoice_serial", mainId));
            } else {
                invoiceService.update(new UpdateWrapper<InvoiceInfo>().set("is_surplus", 1).eq("invoice_serial", mainId + "-" + (Integer.parseInt(serial) - 1)));
            }
        }
        invoiceService.removeById(id);
        return Result.OK("删除成功!");
    }

    /**
     * 提交审核
     *
     * @param data
     * @return
     */
    @PostMapping(value = "/action/{actionType}")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> submit(@RequestBody JSONObject data, @PathVariable String actionType) {
        String id = data.getString("id");
        if (StringUtils.isBlank(id)) {
            return Result.error("未发现要操作的数据");
        } else {
            InvoiceInfo invoiceInfo = invoiceService.getById(id);
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if (actionType.equals("submit")) {//提交审核
                invoiceInfo.setStatus(2);
            } else if (actionType.equals("approved")) {//审核通过
                invoiceInfo.setStatus(3);
                invoiceInfo.setCheckUser(sysUser.getUsername());
                invoiceInfo.setCheckDate(new Date());
            } else if (actionType.equals("reject")) {//驳回
                invoiceInfo.setStatus(1);
                invoiceInfo.setIsReject(1);//打上驳回标记
                invoiceInfo.setCheckUser(sysUser.getUsername());
                invoiceInfo.setCheckDate(new Date());
            } else if (actionType.equals("revoke")) {//撤销开票
                invoiceInfo.setStatus(3);
                invoiceInfo.setInvoiceAttr(null);
                invoiceInfo.setInvoiceDate(null);
                invoiceInfo.setInvoiceNumber(null);
                invoiceInfo.setInvoiceType(null);
                invoiceInfo.setCheckUser(sysUser.getUsername());
                invoiceInfo.setCheckDate(new Date());
                UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
                costInfoUpdateWrapper.set("s_code", 4);
                costInfoUpdateWrapper.set("status", "开票申请中");
                costInfoUpdateWrapper.eq("type", "ys");
                costInfoUpdateWrapper.in("id", Arrays.asList(invoiceInfo.getCostIds().split(",")));
                costInfoService.update(costInfoUpdateWrapper);
            } else if (actionType.equals("cancel")) {//撤销审核
                invoiceInfo.setStatus(2);
                invoiceInfo.setCheckUser(sysUser.getUsername());
                invoiceInfo.setCheckDate(new Date());
            }
            boolean b = invoiceService.updateById(invoiceInfo);
            return b ? Result.OK("操作成功!") : Result.error("操作失败");
        }

    }

    /**
     * 开票
     *
     * @param invoiceInfoVo
     * @return
     */
    @PostMapping(value = "/bill")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> bill(@RequestBody InvoiceInfoVO invoiceInfoVo) {
        if (StringUtils.isAnyBlank(invoiceInfoVo.getId(), invoiceInfoVo.getInvoiceNumber(),
                invoiceInfoVo.getInvoiceAttr(), invoiceInfoVo.getInvoiceDate(),
                invoiceInfoVo.getInvoiceType(), invoiceInfoVo.getCostIds())) {
            return Result.error("缺少开票信息，请检查后重试");
        }
        InvoiceInfo invoiceInfo = new InvoiceInfo();
        BeanUtils.copyProperties(invoiceInfoVo, invoiceInfo);
        //状态改为已开票
        invoiceInfo.setStatus(4);

        UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
        costInfoUpdateWrapper.set("s_code", 5);
        costInfoUpdateWrapper.set("status", "已开票");
        costInfoUpdateWrapper.eq("type", "ys");
        costInfoUpdateWrapper.in("id", Arrays.asList(invoiceInfoVo.getCostIds().split(",")));
        costInfoService.update(costInfoUpdateWrapper);
        boolean b = invoiceService.updateById(invoiceInfo);
        return b ? Result.OK().success("开票成功") : Result.error("开票失败");
    }

    /**
     * 继续开票
     *
     * @param invoiceInfoVo
     * @return
     */
    @PostMapping(value = "/continue/bill")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> continueBill(@RequestBody InvoiceInfoVO invoiceInfoVo) {
        if (StringUtils.isAnyBlank(invoiceInfoVo.getId(),
                invoiceInfoVo.getAmount(),
                invoiceInfoVo.getCnyAmount(),
                invoiceInfoVo.getActualAmount(),
                invoiceInfoVo.getCostIds()
        )) {
            return Result.error("开票信息不全请重试");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        InvoiceInfo invoiceInfo = new InvoiceInfo();
        BeanUtils.copyProperties(invoiceInfoVo, invoiceInfo);
        String invoiceSerial = invoiceInfo.getInvoiceSerial();
        if (invoiceSerial.split("-").length == 2) {
            invoiceInfo.setInvoiceSerial(invoiceSerial.split("-")[0] + "-" + (Integer.parseInt(invoiceSerial.split("-")[1]) + 1));
        } else {
            invoiceInfo.setInvoiceSerial(invoiceSerial.split("-")[0] + "-1");
        }
        invoiceInfo.setId(null);
        invoiceInfo.setCreateTime(new Date());
        invoiceInfo.setCreateBy(sysUser.getUsername());
        invoiceInfo.setSysOrgCode(sysUser.getOrgCode());
        //开票申请中状态
        invoiceInfo.setStatus(2);
//        invoiceInfo.setInvoiceSerial(getBillNumber());
        String actualAmount = invoiceInfo.getActualAmount();
        String amount = invoiceInfo.getAmount();
        //部分开票
        if (!actualAmount.equals(amount)) {
            invoiceInfo.setFeeStatus(2);//部分开票
            invoiceInfo.setIsSurplus(1);//打上有剩余未开票标记
            String parentId = StringUtils.isBlank(invoiceInfoVo.getParentId()) ? invoiceInfoVo.getId() : invoiceInfoVo.getParentId();
            invoiceService.update(new UpdateWrapper<InvoiceInfo>().set("is_surplus", 0).eq("id", invoiceInfoVo.getId()));
            invoiceInfo.setParentId(parentId);
            invoiceService.save(invoiceInfo);
        } else {
            invoiceInfo.setFeeStatus(1);//全部
            invoiceInfo.setIsSurplus(0);//打上没有未开票标记
            UpdateWrapper<InvoiceInfo> updateWrapper = new UpdateWrapper();
            updateWrapper.set("is_surplus", 0);
            updateWrapper.eq("id", invoiceInfoVo.getId());
            //更新之前费用账单剩余未开票标记为0
            invoiceService.update(updateWrapper);
            invoiceService.save(invoiceInfo);
        }
        return Result.OK().success("操作成功");
    }

    /**
     * 开票申请/保存
     *
     * @param invoiceInfoVo
     * @return
     */
    @PostMapping(value = "/{subType}")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> add(@RequestBody InvoiceInfoVO invoiceInfoVo, @PathVariable String subType) {
        if (invoiceInfoVo.getIds().size() == 0) {
            return Result.error("操作失败,请选择开票费用的明细");
        } else if (StringUtils.isAnyBlank(invoiceInfoVo.getCnyAmount(), invoiceInfoVo.getAmount())) {
            return Result.error("操作失败,请重新选择后重试");
        } else if (StringUtils.isBlank(invoiceInfoVo.getActualAmount())) {
            return Result.error("操作失败,请填写开票金额后重试");
        } else if (StringUtils.isAnyBlank(invoiceInfoVo.getCurrency(), invoiceInfoVo.getCnyAmount(), invoiceInfoVo.getAmount()
                , invoiceInfoVo.getSettlementCompany())) {
            return Result.error("操作失败,信息不全请重试");
        }
        InvoiceInfo invoiceInfo = new InvoiceInfo();
        BeanUtils.copyProperties(invoiceInfoVo, invoiceInfo);
        invoiceInfo.setInvoiceSerial(getBillNumber());
        String actualAmount = invoiceInfo.getActualAmount();
        String amount = invoiceInfo.getAmount();
        //部分开票
        if (!actualAmount.equals(amount)) {
            invoiceInfo.setFeeStatus(2);//部分开票
            invoiceInfo.setIsSurplus(1);//打上有剩余未开票标记
        } else {
            invoiceInfo.setFeeStatus(1);//全部
            invoiceInfo.setIsSurplus(0);//打上没有未开票标记
        }
        //判断是保存还是直接提交审核
        if (subType.equals("save")) {
            invoiceInfo.setStatus(1);
        } else if (subType.equals("apply")) {
            invoiceInfo.setStatus(2);
        }
        //保存选择费用的ids
        String str = String.join(",", invoiceInfoVo.getIds());
        invoiceInfo.setCostIds(str);
        //更新费用信息的状态
        UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
        costInfoUpdateWrapper.set("s_code", 4);
        costInfoUpdateWrapper.set("status", "开票申请中");
        costInfoUpdateWrapper.eq("type", "ys");
        costInfoUpdateWrapper.in("id", invoiceInfoVo.getIds());
        costInfoService.update(costInfoUpdateWrapper);
        boolean b = false;
        if (subType.equals("edit")) {
            invoiceInfo.setCreateTime(new Date());
            b = invoiceService.updateById(invoiceInfo);
            //更新费用信息的状态
            UpdateWrapper<CostInfo> costInfoUpdateWrapper1 = new UpdateWrapper<>();
            costInfoUpdateWrapper1.set("s_code", 3);
            costInfoUpdateWrapper1.set("status", "审核成功");
            costInfoUpdateWrapper1.eq("type", "ys");
            costInfoUpdateWrapper1.in("id", invoiceInfo.getCostIds());
            costInfoService.update(costInfoUpdateWrapper);
        } else {
            b = invoiceService.save(invoiceInfo);
        }

        return b ? Result.OK().success("操作成功") : Result.error("操作失败");
    }


    /**
     * 根据ID查询相应的费用明细数据
     *
     * @param id
     * @return
     */
    @GetMapping(value = "/query/costinfo")
    public Result list(String id) {
        if (StringUtils.isBlank(id)) {
            return Result.error("未发现要操作数据的单号");
        }
        InvoiceInfo invoiceInfo = invoiceService.getById(id);
        String costIds = invoiceInfo.getCostIds();
        List costIdsList = Arrays.asList(costIds.split(","));
        List costInfosByIds = costInfoService.getCostInfosByIds(costIdsList);
        return Result.OK(costInfosByIds);
    }

    /**
     * 生成发票流水号
     *
     * @return
     */
    private synchronized String getBillNumber() {
        StringBuffer sb = new StringBuffer().append("FPS");
        String yymmdd = DateTimeFormatter.ofPattern("yyMMdd").format(LocalDate.now());
        sb.append(yymmdd);
        String s = sb.toString();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.like("invoice_serial", s);
        int count = invoiceService.count(queryWrapper);
        String billNumber = String.format("%0" + 4 + "d", count + 1);
        return sb.append(billNumber).toString();
    }
}
